import java.lang.reflect.*;
import java.util.*;

/*
 *  @author  Alpesh Mistry  <apm1dec@gmail.com>
 *  @author  Ankur Kothari  <a.kothari711@gmail.com>
 *  @author  Elman Mansimov <elman.mansimov@gmail.com>
 *  @author  Michelle Pan   <panmiche@gmail.com>
 *  @version 1.0
 *  @since   2012-03-03
 */

public class JShell {
	
	/**
	 * FileSystem Object initialized to null.
	 * Stores an instance of FileSystem. 
	 */
	private static FileSystem mockSystem = null;
	
	/**
	 * Returns a String[] array that makes processing user
	 * input easier.
	 * 
	 * This method parses the String argument based on the characters
	 * ' ', '\', '"' and '>' with the help of an arraylist. This is done 
	 * to account for all kinds of user input. If the double quotes are
	 * uneven in number, then a messaged is printed making the user aware
	 * of the issue. Also String array of length 1 with an empty String 
	 * as its element is returned. that draw the image will incrementally
	 * paint on the screen. 
	 *
	 * @param  line A String that stores the user input for processing.
	 * @return A String array that contains the processed String argument.
	 * @see java.lang.String
	 * @see java.util.Arrays
	 * @see	java.lang.Character
	 */
	
	private String[] parseInput(String line) {
		
		char[] charArr = line.trim().toCharArray();
		String eachWord = "";
		ArrayList<String> lineList = new ArrayList<String>();
		boolean inQuotes = false;
		boolean inSlash = false;
		boolean checkSpace1 = false;
		boolean checkSpace2 = false;
		int i;
		String[] inputArray = null;
		String[] emptyStr = {""};
		
		for (i = 0; i < charArr.length; i++) {
			
			if (charArr[i] == '"') 				
				inQuotes = !inQuotes;
			
			else if (charArr[i] == '\\' && !inQuotes){
				
				try {
					if (inSlash && charArr[i] != '\\'){
						
						eachWord += charArr[i];
					}
					
					checkSpace1 = charArr[i+1] == ' ';
					checkSpace2 = charArr[i+2] == ' ';
					
					if (checkSpace1 && checkSpace2) {
						inSlash = false;
					} else {
						eachWord += charArr[i+1];
						i += 1;
					}
				} catch(Exception e) {}
				
			}else if (!inQuotes && charArr[i] == '>') {
				if (!eachWord.equals("")) {
					lineList.add(eachWord);
					eachWord = "";
				}
				
				eachWord += charArr[i];
				
				if (charArr[i+1] == '>') {
					eachWord += charArr[i+1];
					i += 1;          
				}
				
				lineList.add(eachWord);
				eachWord = "";
				
			} else if (!inQuotes && charArr[i] == ' ' && !inSlash) {
				
				if (!eachWord.equals("")) {
					
					lineList.add(eachWord);
					eachWord = "";
				}
			} else
				eachWord += charArr[i];
		}
		
		if (eachWord != "")
			lineList.add(eachWord);
		
		inputArray = new String[lineList.size()];
		inputArray = lineList.toArray(inputArray);
		
		if (inQuotes){
			System.out.println("Unmatched \".");
			return emptyStr;
		} else 
			return inputArray;
	}
	
	/**
	 * Reads the user input and executes the commands appropriately.
	 * 
	 * This method parses the user input with the help of parseInput 
	 * method. mockSystem gets an instance of FileSystem 
	 * and find and execute the commands depending on the user input.
	 * This method keeps n asking for user input until the user has 
	 * entered the String "exit". 
	 *
	 * @throws InstantiationException    If an instance of FileSystem can't be made.
	 * @throws IllegalAccessException    If the code tries execute a method,
	 *                                   does not exist in the class or is an abstract method
	 *                                   in the class.
	 * @throws SecurityException         If the code tries to access methods that it
	 * 									 is not allowed to. 
	 *                                   method or object that is set private
	 *                                   and doesn't give permission to access it.                                     
	 * @throws InvocationTargetException If the given method doesn't exist or can't be invoked.
	 * @see java.lang.reflect
	 */
	
	public void startShell() 
	throws 	InstantiationException,
	IllegalAccessException, 
	SecurityException,
	InvocationTargetException {
		
		mockSystem = FileSystem.getInstance();
		Scanner reader = new Scanner(System.in);		
		String cmdGiven = "start";
		String[] inArr = null;
		String userInput = "";
		
		while (!cmdGiven.equals("exit")) {
			
			if (FileSystem.currDir.getParent() != null)
				System.out.print(FileSystem.currDir.getFullPath()	+ "# ");
			else
				System.out.print("/" + "# ");
			
			userInput = reader.nextLine();
			inArr = parseInput(userInput);
			cmdGiven = inArr[0];
			
			if (!cmdGiven.equals("exit") && !cmdGiven.equals(""))
				JShell.mockSystem.selectFunction(inArr);
		}
		reader.close();
	}
	
	/**
	 * This the main method from where the code execution begins.
	 * 
	 * Creates a new JShell object and executes an instance method
	 * startShell which has been defined already. It handles the user input
	 * and act accordingly.
	 *
	 * @param args Is an String array that stores the code to be 
	 * 			   executed in this method.
	 * @throws InstantiationException    If an instance of FileSystem can't be made.
	 * @throws IllegalAccessException    If the code tries execute a method,
	 *         			                 does not exist in the class or is an abstract method
	 *                                   in the class.
	 * @throws SecurityException         If the code tries to access methods that it
	 * 						             is not allowed to. 
	 *                                   method or object that is set private
	 *                                   and doesn't give permission to access it.                                     
	 * @throws InvocationTargetException If the given method doesn't exist or can't be invoked.
	 * @see java.lang.reflect
	 */
	
	public static void main(String[] args) 
		throws 	InstantiationException,
				IllegalAccessException, 
				SecurityException,
				InvocationTargetException {

		JShell shellRun = new JShell();
		shellRun.startShell();
	}
}
